//////////////////////////////////////////////////////////////////////
////                                                              ////
////  SysGenDataDecoder.v                                         ////
////                                                              ////
////                                                              ////
////  This file is part of the "Pico E12" project                 ////
////  http://www.picocomputing.com                                ////
////                                                              ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
////                                                              ////
//// Copyright (C) 2005, Picocomputing, Inc.                      ////
//// http://www.picocomputing.com/                                ////
////                                                              ////
//// This source file may be used and distributed without         ////
//// restriction provided that this copyright statement is not    ////
//// removed from the file and that any derivative work contains  ////
//// the original copyright notice and the associated disclaimer. ////
////                                                              ////
//// This source file is free software; you can redistribute it   ////
//// and/or modify it under the terms of the GNU Lesser General   ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any   ////
//// later version.                                               ////
////                                                              ////
//// This source is distributed in the hope that it will be       ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
//// PURPOSE.  See the GNU Lesser General Public License for more ////
//// details.                                                     ////
////                                                              ////
//// You should have received a copy of the GNU Lesser General    ////
//// Public License along with this source; if not, download it   ////
//// from http://www.opencores.org/lgpl.shtml                     ////
////                                                              ////
////////////////////////////////////////////////////////////////////JF

//This module generates the addr, data_in, data_out, re and we signals for the Systen Generator interface
`include "PicoDefines.v"
module SysGenDataDecoder(MemRead, MemWrite, MemAddress, DataIn, DataOut, SysGenClkSelect,
                         SysGen_addr, SysGen_bank_sel, SysGen_data_in, SysGen_data_out, SysGen_pci_clk, SysGen_re, SysGen_we);


input MemRead;                         //Card -> Host Read
input MemWrite;                        //Host -> Card Write
input [31:1]MemAddress;                //Memory Address
input [15:0]DataIn;                    //Host -> Card Data In
output [15:0]DataOut;                  //Card -> Host Data Out

output SysGenClkSelect;                //System Generator Step Clock Select (0 - Pulsed, 1 - Free Running)z

output [23:0]SysGen_addr;              //System Generator Address Out
output [7:0]SysGen_bank_sel;           //System Generator Bank Select
output [31:0]SysGen_data_in;           //System Generator Data In
input [31:0]SysGen_data_out;           //System Generator Data Out
input SysGen_pci_clk;                  //System Generator PCI Clock
output SysGen_re;                      //System Generator Read Enable
output SysGen_we;                      //System Generator Write Enable

reg SysGenClkSelect;

reg [7:0]SysGen_bank_sel;
reg [31:0]SysGen_data_in;
reg [31:0]SysGenDataOut;
reg SysGen_re;
reg SysGen_we;

wire [15:0]SysGenBankDataOut;

reg ReadLockout;
reg ReadReset;
reg WriteLockout;
reg WriteReset;

wire SysGenSelect;
wire RawSysGenRead;
wire RawSysGenWrite;
wire OddWord;
wire EvenWord;

wire [15:0]SysGenDataOutLow;
wire [15:0]SysGenDataOutHigh;

//systhesis attribute INIT of SysGenClkSelect is 0;
//synthesis attribute INIT of SysGen_bank_sel is 8'h00;
//synthesis attribute INIT of SysGen_data_in is 32'h00000000;
//synthesis attribute INIT of SysGenDataOut is 32'h00000000;
//synthesis attribute INIT of SysGen_re is 0;
//synthesis attribute INIT of SysGen_we is 0;
//synthesis attribute INIT of ReadLockout is 0;
//synthesis attribute INIT of ReadReset is 0;
//synthesis attribute INIT of WriteLockout is 0;
//synthesis attribute INIT of WriteReset is 0;


//-------------Address and Function Decoding----------------
assign EvenWord = MemAddress[1] == 0;
assign OddWord = MemAddress[1] == 1;
assign SysGenSelect = (MemAddress[31:2] <= `SYSGEN_MAX_ADDRESS) && (MemAddress[31:2] >= `SYSGEN_MIN_ADDRESS);
assign RawSysGenRead = (SysGenSelect) && (MemRead);
assign RawSysGenWrite = (SysGenSelect) && (MemWrite);
assign SysGenBankRead = (MemRead) && (MemAddress[31:1] == `SYSGEN_BANK_ADDRESS);
assign SysGen_addr[23:0] = MemAddress[23:2] - 1;


//-----------------Write Enable Controller------------------
//Write Enable is driven high for one rising edge of the System Generator clock
always @(posedge SysGen_pci_clk)
   WriteReset <= ~((RawSysGenWrite) && (OddWord));

always @(negedge SysGen_pci_clk)
begin
   if (WriteReset) begin                                                  //Reset everything when not reading
	   WriteLockout <= 0;      
		SysGen_we <= 0;
   end
else
   if (WriteLockout) begin                                               //Reset re (read enable)
	   SysGen_we <= 0;                                                    //Read Cycle is Active and Lockout is High
   end
else
   begin
      SysGen_we <= 1;                                                    //Read Cycle is Active and Lockout is Low
	   WriteLockout <= 1;
   end
end

//-----------------Read Enable Controller-------------------
//Read Enable is driven high for one rising edge of the System Generator clock

//ReadReset eliminates some race logic when combining asynchronous and synchronous signals
always @(posedge SysGen_pci_clk)
   ReadReset <= ~((RawSysGenRead) && (EvenWord));

always @(negedge SysGen_pci_clk)
begin
   if (ReadReset) begin                                                  //Reset everything when not reading
	   ReadLockout <= 0;      
		SysGen_re <= 0;
   end
else
   if (ReadLockout) begin                                                //Reset re (read enable)
	   SysGen_re <= 0;                                               //Read Cycle is Active and Lockout is High
   end
else
   begin
      SysGen_re <= 1;                                                    //Read Cycle is Active and Lockout is Low
	   ReadLockout <= 1;
   end
end


//---------------------Data Out Latch----------------------
always @(SysGen_re or SysGenDataOut or SysGen_data_out)
   if (SysGen_re) SysGenDataOut[31:0] <= SysGen_data_out[31:0];          //32 Bit Transparent Latch to Hold SysGenDataOut


//---------------------Data In Latch-----------------------
always @(posedge MemWrite)                                            
begin
   if (SysGenSelect) begin
	   if (MemAddress[1] == 0) SysGen_data_in[15:0] <= DataIn[15:0];      //Even word write (don't send to sysgen yet)
   else																					  
      if (MemAddress[1] == 1) SysGen_data_in[31:16] <= DataIn[15:0];     //Odd word write (write cycle will be triggered)
   end
end


//--------------------Bank Selection-----------------------
always @(posedge MemWrite)
begin
     if (MemAddress[31:1] == `SYSGEN_BANK_ADDRESS) begin
	       SysGen_bank_sel[7:0] <= DataIn[7:0];
          SysGenClkSelect <= DataIn[15];
     end
end


//--------------------Data Out Muxes-----------------------
assign SysGenDataOutLow[15:0] = ((RawSysGenRead) && (EvenWord))?SysGenDataOut[15:0] : 16'b0;
assign SysGenDataOutHigh[15:0] = ((RawSysGenRead) && (OddWord))?SysGenDataOut[31:16] : 16'b0;

assign SysGenBankDataOut[7:0] = (SysGenBankRead)?SysGen_bank_sel[7:0] : 8'b0;
assign SysGenBankDataOut[14:8] = 7'b0;
assign SysGenBankDataOut[15] = (SysGenBankRead)?SysGenClkSelect : 1'b0;


//-----------------------Data Out--------------------------
assign DataOut[15:0] = (SysGenDataOutLow[15:0] | SysGenDataOutHigh[15:0] | SysGenBankDataOut[15:0]);


endmodule